#include <string.h>
#include "tuya_tools.h"

#include "tkl_network_manager.h"

#include "tal_gpio.h"
#include "tal_memory.h"
#include "tal_sw_timer.h"
#include "tal_zcl_group.h"
#include "tal_network_mgr.h"
#include "tal_data_send.h"
#include "tal_data_receive.h"
#include "tal_attribute_rw.h"
#include "tal_endpoint_register.h"
#include "tal_reset_factory.h"
#include "tal_heartbeat.h"
#include "tal_firmware_cfg.h"
#include "tal_uart.h"
#include "tal_zll_commissioning.h"
#include "tal_error_code.h"
#include "tal_sleep.h"
#include "tal_log.h"

#include "app_common.h"
#include "app_led.h"
#include "app_ias_zone.h"
#include "app_dev_register.h"
#include "app_gpio.h"
#include "app_battery.h"
#include "tal_mf_test.h"
#include "tal_zll_commissioning.h"

#define MAIN_CALLBACK_DEBUG   1

#if MAIN_CALLBACK_DEBUG
#include "tkl_uart.h"
#include "tlprintf.h"
#define tal_main_debug(...)     tal_log_print_raw(__VA_ARGS__)
#else
#define tal_main_debug(...)
#endif

//button
#define GPIO_APP_BUTTON      TUYA_GPIO_NUM_16//PC0
//led
#define GPIO_APP_STATUS_LED  TUYA_GPIO_NUM_18//PC2
#define GPIO_APP_NET_LED     TUYA_GPIO_NUM_19//PC3
//
#define GPIO_APP_ALARM_PIN   TUYA_GPIO_NUM_28//PD4
#define GPIO_APP_ZLL_SCAN_PIN           TUYA_GPIO_NUM_13 //PB5
#define GPIO_APP_ZLL_FACTORY_NEW_PIN    TUYA_GPIO_NUM_12 //PB4

//event id
TIMER_ID power_on_event_id;
TIMER_ID etimer_zll_target_delay_add_group_event_id;
TAL_ZLL_DEV_LIST_T g_zll_dev_tbl;
extern TIMER_ID mf_delay_send_event_id;
extern BOOL_T sys_init_finish_flag;

STATIC VOID_T __power_on_event(TIMER_ID timer_id, VOID_T *arg);
extern VOID_T __mf_delay_send_event(TIMER_ID timer_id, VOID_T *arg);

STATIC VOID_T __tuya_uart_debug_init(VOID_T);
STATIC VOID_T __network_info_print(VOID_T);
VOID_T __tuya_led_init(VOID_T);
VOID_T __tuya_gpio_init(VOID_T);
VOID_T __tuya_battery_init(VOID_T);

#define APP_HEAP_SIZE 9*1024
STATIC UINT8_T gs_heap[APP_HEAP_SIZE];
VOID_T tkl_memory_cfg(UINT8_T **out_buff, UINT32_T *out_buff_len)
{
    *out_buff = gs_heap;
    *out_buff_len = APP_HEAP_SIZE;
}

STATIC VOID_T __power_on_event(TIMER_ID timer_id, VOID_T *arg)
{
    tal_main_debug("into __power_on_event\r\n");
    dev_power_on_indicate();
    app_gpio_preheat_init();
}

STATIC VOID_T __network_info_print(VOID_T)
{
    TKL_NWK_BASIC_INFO_T nwk_info;
    tkl_zg_nwk_base_info_get(&nwk_info);
    tal_main_debug("power_on_online, \npan-id=0x%x \nch=%d \naddr=%x \ntx_power=%d\r\n", 
                    nwk_info.panid, 
                    nwk_info.radio_channel,
                    nwk_info.nwk_addr,
                    nwk_info.radio_power);
}

STATIC VOID_T __tuya_uart_debug_init(VOID_T)
{
    TAL_UART_CFG_T uart_cfg;
    tal_system_memset(&uart_cfg, 0, SIZEOF(TAL_UART_CFG_T));
        uart_cfg.rx_buffer_size = 128,
        uart_cfg.open_mode = 0,
        uart_cfg.base_cfg.baudrate = 115200,
        uart_cfg.base_cfg.parity = TUYA_UART_PARITY_TYPE_NONE,
        uart_cfg.base_cfg.databits = TUYA_UART_DATA_LEN_8BIT;
        uart_cfg.base_cfg.stopbits = TUYA_UART_STOP_LEN_1BIT,
        uart_cfg.base_cfg.flowctrl = TUYA_UART_FLOWCTRL_NONE;

        tal_uart_init(TUYA_UART_NUM_0, &uart_cfg);
}

VOID_T __tuya_led_init(VOID_T)
{
    //led init
    APP_LED_INFO_T led_info;
    led_info.status_led.enabled = TRUE;
    led_info.status_led.driver_flag = TRUE;
    led_info.status_led.pin_num = GPIO_APP_STATUS_LED;
    led_info.net_led.enabled = TRUE;
    led_info.net_led.driver_flag = TRUE;
    led_info.net_led.pin_num = GPIO_APP_NET_LED;
    led_info.alarm_type = LED_INDICATE_TYPE_ONCE;
    led_info.tamper_type = LED_INDICATE_TYPE_ONCE;
    led_info.trouble_type = LED_INDICATE_TYPE_ONCE;
    if (OPRT_OK == app_led_oem_init(&led_info)) {
        tal_main_debug("led init ok!!!\r\n");
        return;
    }
    tal_main_debug("led init error!!!\r\n");
}

VOID_T __tuya_gpio_init(VOID_T)
{
    //ALARM
    APP_GPIO_INFO_T gpio_info;
    
    gpio_info.alarm.enabled = TRUE;
    gpio_info.alarm.driver_flag = FALSE;
    gpio_info.alarm.pin_num = GPIO_APP_ALARM_PIN;

    gpio_info.key.enabled = TRUE;
    gpio_info.key.driver_flag = FALSE;
    gpio_info.key.pin_num = GPIO_APP_BUTTON;

    gpio_info.zll_scan_key.enabled = TRUE;
    gpio_info.zll_scan_key.driver_flag = TRUE;
    gpio_info.zll_scan_key.pin_num = GPIO_APP_ZLL_SCAN_PIN;

    gpio_info.zll_factory_new_key.enabled = TRUE;
    gpio_info.zll_factory_new_key.driver_flag = TRUE;
    gpio_info.zll_factory_new_key.pin_num = GPIO_APP_ZLL_FACTORY_NEW_PIN;

    if (OPRT_OK == app_gpio_oem_init(&gpio_info)) {
        tal_main_debug("alarm tamper init ok!!!\r\n");
        return;
    }
    tal_main_debug("alarm tamper init error!!!\r\n");
}

VOID_T __tuya_battery_init(VOID_T)
{
    UINT32_T list_ch = 1;
    APP_BATTERY_INFO_T bat_info = {.cap_first_delay_time = 60 * 1000,
    .cap_max_period_time = 3 * 60 * 1000,
    .adc.ch_nums = 1,
    .adc.ref_vol = 3300,
    .adc.width = 12,
    .adc.freq = 0,
    .adc.type = TUYA_ADC_INNER_SAMPLE_VOL,
    .adc.ch_list.data = list_ch};

    app_battery_config_init(&bat_info, NULL, 0);
    tal_main_debug("battery init ok!!!\r\n");
}

VOID_T __tuya_pre_sleep_cb(VOID_T)
{
    tal_main_debug("pre_sleep_cb!!!\r\n");
}

VOID_T __tuya_post_sleep_cb(VOID_T)
{
    tal_main_debug("post_sleep_cb!!!\r\n");
}

OPERATE_RET tuya_init_first(VOID_T)
{
    tal_main_debug("/*********first init*********/\r\n");
    //uart init
    // __tuya_uart_debug_init();
    tal_log_create_manage_and_init(TAL_LOG_LEVEL_DEBUG, 128, Tl_printf);
    //zigbee endpont init
    dev_zigbee_init();
    //disable beacon test
    tal_mf_test_disable_beacon_test();
    //disable network recovery
    tal_zg_nwk_recovery_disable(TRUE);

    tal_zll_initiator_touchlink_init();

    tal_zg_nwk_join_by_installcode_only_enable(FALSE);

    TUYA_SLEEP_CB_T  sleep_cb = {
        .pre_sleep_cb = __tuya_pre_sleep_cb,
        .post_wakeup_cb = __tuya_post_sleep_cb,
    };
    tal_cpu_sleep_callback_register(&sleep_cb);

    return OPRT_OK;
}

STATIC VOID_T __zll_add_group_callback(TAL_SEND_ST_E st, TAL_ZG_SEND_DATA_T *data)
{
    TAL_ZG_SEND_DATA_T send_data;

    send_data.zcl_id = 101;
    tal_main_debug("__zll_add_group_callback %d\r\n",st);
    if(st == SEND_ST_OK) {
        tal_zg_clear_send_data(ZG_CLEAR_ALL_ZCL_ID, &send_data.zcl_id);
    }
}

STATIC VOID_T app_remoteControl_AddGroup(UINT16_T dst_addr, UINT8_T dst_ep, UINT16_T group_id)
{
    tal_main_debug("Run into : %s\r\n",__FUNCTION__);
    TAL_ZG_SEND_DATA_T send_data;
    UINT8_T i = 0;
    if(group_id == 0)return;
    tal_system_memset(&send_data, 0, sizeof(TAL_ZG_SEND_DATA_T));

    send_data.qos = QOS_VIP_0;
    send_data.zcl_id = 101;
    send_data.direction = ZG_ZCL_DATA_CLIENT_TO_SERVER;
    send_data.command_id = CMD_ADD_GROUP_COMMAND_ID;
    send_data.frame_type = ZG_ZCL_FRAME_TYPE_SPEC_TO_CLUSTER;
    send_data.addr.mode = SEND_MODE_DEV;
    send_data.addr.type.dev.dst_addr = dst_addr;
    send_data.addr.type.dev.src_ep = 1;
    send_data.addr.type.dev.dst_ep = dst_ep;
    send_data.addr.type.dev.cluster_id = CLUSTER_GROUPS_CLUSTER_ID;
    send_data.delay_time = 0;
    send_data.random_time = 0;
    send_data.data.private.data[i++] = (group_id  & 0xFF);
    send_data.data.private.data[i++] = (group_id >> 8) & 0xFF;
    send_data.data.private.data[i++] = 0;
    send_data.data.private.len = i;
    tal_zg_clear_send_data(ZG_CLEAR_ALL_ZCL_ID, &send_data.zcl_id);
    tal_zg_send_data(&send_data, __zll_add_group_callback, 3000);
}

STATIC VOID_T app_zll_delay_event_handler(TIMER_ID timer_id, VOID_T *arg){
    tal_main_debug("Run into : %s\r\n",__FUNCTION__);
    for(UINT8_T i=0; i<g_zll_dev_tbl.dev_sums;i++){
        app_remoteControl_AddGroup(g_zll_dev_tbl.list[i].short_addr,0xff,0x4003);
        // app_remoteControl_on(0x4003,0xff);
    }
}

OPERATE_RET tuya_init_second(VOID_T)
{
    tal_main_debug("/*********second init*********/\r\n");
    //event init
    tal_sw_timer_create(__power_on_event, NULL, &power_on_event_id);
    tal_sw_timer_create(__mf_delay_send_event, NULL, &mf_delay_send_event_id);
    tal_sw_timer_create(app_zll_delay_event_handler, NULL, &etimer_zll_target_delay_add_group_event_id);
    return OPRT_OK;
}

OPERATE_RET tuya_init_third(VOID_T)
{
    tal_main_debug("/*********third init*********/\r\n");
    return OPRT_OK;
}

OPERATE_RET tuya_init_last(VOID_T)
{
    tal_main_debug("/*********last init*********/\r\n");
    // __tuya_uart_debug_init();

    sys_init_finish_flag = TRUE;

    __tuya_gpio_init();

    __tuya_led_init();

    __tuya_battery_init();

    tal_sw_timer_start(power_on_event_id, 0, TAL_TIMER_ONCE);

    return OPRT_OK;
}

OPERATE_RET tuya_main_loop(VOID_T)
{
    return OPRT_OK;
}

VOID_T vSytickInterruptHook( VOID_T )
{
}

VOID_T vApplicationTickHook( VOID_T )
{
}

TAL_WRITE_RET_E tal_zg_pre_write_attribute_callback(UINT8_T ep_id,
                                                    UINT16_T cluster_id,
                                                    TAL_ATTR_REC_T *attr_rec)
{
    tal_main_debug("pre write callback: cluster 0x%x\r\n", cluster_id);
    return WRITE_RET_SUCCESS;
}

/**
 * @brief post-write attribute callback
 *
 * @param[in] ep_id:      endpoint id
 * @param[in] cluster_id: cluster id
 * @param[in] attr_rec:   point to attribute record 
 * @return write status
 */
TAL_WRITE_RET_E tal_zg_post_write_attribute_callback(UINT8_T ep_id, 
                                                                UINT16_T cluster_id,
                                                                TAL_ATTR_REC_T *attr_rec)
{
     if (IAS_ZONE_ENDPOINT == ep_id) {
         switch (cluster_id) {
             case CLUSTER_IAS_ZONE_CLUSTER_ID: {
                 if( ATTR_IAS_CIE_ADDRESS_ATTRIBUTE_ID == attr_rec->attr_id ) {
                     ias_zone_cie_address_write_callback();
                 }
                 break;
             }
             default: {
                 break;
             }
         }
     }
     return WRITE_RET_SUCCESS;
}

TAL_MSG_RET_E tal_zcl_general_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{
    tal_main_debug("app gen msg cb: cluster 0x%x, cmd %d\r\n", msg->cluster, msg->command);
    return ZCL_MSG_RET_SUCCESS;
}

TAL_MSG_RET_E tal_zcl_specific_msg_recv_callback(TAL_ZCL_MSG_T *msg)
{

    ZIGBEE_CMD_E app_cmd_type = ZIGBEE_CMD_SINGLE;
    if (msg->mode == ZG_UNICAST_MODE)
    {
        app_cmd_type = ZIGBEE_CMD_SINGLE;
    }
    else
    {
        app_cmd_type = ZIGBEE_CMD_GROUP;
    }

    switch (msg->cluster)
    {
        case CLUSTER_GROUPS_CLUSTER_ID: {
            //group_cluster_command_handler(msg->command, msg->payload, msg->length, app_cmd_type, msg->direction);
            break;
        }
        case CLUSTER_IAS_ZONE_CLUSTER_ID: {
            ias_zone_cluster_server_command_handler(msg->command, msg->payload, msg->length, app_cmd_type);
            break;
        }
        default:
            break;
    }
    return ZCL_MSG_RET_SUCCESS;
}

VOID_T tal_zg_nwk_status_changed_callback(TAL_ZG_NWK_STATUS_E status)
{
    switch(status)
    {
        case TAL_ZG_NWK_POWER_ON_LEAVE: { 
            tal_main_debug("---app nwk_power_on_leave---\r\n");
            break;
        }
        case TAL_ZG_NWK_POWER_ON_ONLINE: {
            tal_main_debug("---app nwk_power_on_onlie---\r\n");
            __network_info_print();
            app_battery_start();
            break;
        }
        case TAL_ZG_NWK_JOIN_START: {
            tal_main_debug("---app nwk_join_start---\r\n");
            dev_start_join_indicate(TRUE);
            break;
        }
        case TAL_ZG_NWK_JOIN_OK: {
            tal_main_debug("---app nwk_join_ok---\r\n");
            __network_info_print();
            dev_join_success_indicate();
            app_battery_start();
            break;
        }
        case TAL_ZG_NWK_REJOIN_OK: {
            tal_main_debug("---app nwk_rejoin_ok---\r\n");
            app_battery_start();
            break;
        }
        case TAL_ZG_NWK_JOIN_TIMEOUT: {
            dev_start_join_indicate(FALSE);
            tal_main_debug("---app nwk_join_timeout---\r\n");
            break;
        }
        case TAL_ZG_NWK_LOST: {
            tal_main_debug("---app nwk_lost---\r\n");
            break;
        }
        case TAL_ZG_NWK_REMOTE_LEAVE: {
            tal_main_debug("---app nwk_remote_leave---\r\n");
            break;
        }
        case TAL_ZG_NWK_LOCAL_LEAVE: {
            tal_main_debug("---app nwk_local_leave---\r\n");
            break;
        }
        case TAL_ZG_NWK_MF_TEST_LEAVE: {
            tal_main_debug("---nwk_mf_test_leave---\r\n");
            break;
        }
        default: {
            break;
        }
    }
}

VOID_T tal_zg_reset_factory_default_callback(TAL_RESET_TYPE_T type)
{
    tal_main_debug("receive reset to factory default cmd %d\r\n", type);
}

VOID_T tal_beacon_mf_test_callback(VOID_T)
{
    tal_main_debug("enter beacon test\r\n");
}

VOID_T tal_mf_test_pre_start_callback(VOID_T *args)
{
    tal_main_debug("enter dongle-beacon start\r\n");
}

VOID_T tal_mf_test_end_callback(UINT8_T *data)
{
    tal_main_debug("enter dongle-beacon end, value %d\r\n", *data);
}

BOOL_T tal_mf_test_enable_read_install_code(VOID_T)
{
    return TRUE;
}


#include "tkl_platform_types.h"

BOOL_T app_print_get_cfg(UINT8_T *print_type, UINT8_T *disable_irq, GPIO_PORT_PIN_T *gpio)
{
    gpio->port = PORT_C;
    gpio->pin = PIN_4;
    *print_type = 0;
    *disable_irq = 1;
#if UART_PRINTF_MODE
    return 1;
#else
    return 0;
#endif
}



VOID_T tal_zll_initiator_commissioning_complete_callback(TAL_ZLL_SCAN_RESULT_E result, TAL_ZLL_DEV_LIST_T* list)
{
    tal_main_debug("%s: result=%d,sum=%d\r\n", __FUNCTION__, result, (list == NULL) ? 0 : list->dev_sums);
    if (result == TAL_ZLL_TOUCH_REJOIN_SUCESS && list != NULL && list->dev_sums > 0)
    { 
        for(unsigned char i =0;i<list->dev_sums;i++){
            tal_main_debug(">>> zll channel=%d\r\n", list->list[i].channel);
            tal_main_debug(">>> target addr=0x%x\r\n", list->list[i].short_addr);
        }
//            tal_main_debug(">>> zll channel=%d\r\n", list->list[0].channel);
//            tal_main_debug(">>> target addr=0x%x\r\n", list->list[0].short_addr);
        tal_sw_timer_start(etimer_zll_target_delay_add_group_event_id, 5000, TAL_TIMER_ONCE);
        TAL_ZLL_DEV_INFO_T *dev_list = (TAL_ZLL_DEV_INFO_T *)tal_malloc(list->dev_sums * sizeof(TAL_ZLL_DEV_INFO_T));
        if (dev_list != NULL)
        {
            g_zll_dev_tbl.dev_sums = list->dev_sums;
            g_zll_dev_tbl.list = dev_list;
            tal_system_memcpy(g_zll_dev_tbl.list, list->list, list->dev_sums * sizeof(TAL_ZLL_DEV_INFO_T));
        }
    }
}

#ifdef MCU_CORE_8258
#if END_DEVICE
/***********************定义该函数表示gpio休眠不保持，需要自己把控休眠节奏********************************/ 
BOOL_T tkl_gpio_output_use_wakeup_mode(TUYA_GPIO_NUM_E pin_id)
{
    if((GPIO_APP_STATUS_LED == pin_id) || (GPIO_APP_NET_LED == pin_id)){
        return TRUE;
    }
    else
    {
        return FALSE;        
    }
}
#endif

/***********************定义该函数用于重新分配管脚中断源，一般与 gpio_int_fast_handle 配合使用用于处理快速中断输入********************************/
BOOL_T tkl_reallocate_gpio_interrupt_source(TUYA_GPIO_NUM_E pin,UINT8_T before_mode,UINT8_T* after_mode)
{
    if(pin == GPIO_APP_ZLL_SCAN_PIN){
        *after_mode = 1;
        return TRUE;
    }
    else{
        *after_mode = 2;
        return TRUE;
    }
    return FALSE;
}


#endif